package wangwenjun.phase3.executor;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/6/22
 */
@Slf4j
public class ShutdownTest {

    @Test
    @DisplayName("test shutdown")
    public void test() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> new Thread(r));
        IntStream.range(0,20).boxed().forEach(i->executorService.submit(()->{
            try {
                ThreadUtil.sleepForSeconds(5);
                log.info("task#{} finish");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        executorService.shutdown();
        log.warn("executorService#shutdown non block");
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test shutdown")
    public void test2() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> new Thread(r));
        IntStream.range(0,5).boxed().forEach(i->executorService.submit(()->{
            try {
                ThreadUtil.sleepForSeconds(5);
                log.info("task#{} finish");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        executorService.shutdown();
        log.warn("executorService#shutdown non block");
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test shutdown & awaitTermination")
    public void test3() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> new Thread(r));
        IntStream.range(0,5).boxed().forEach(i->executorService.submit(()->{
            try {
                ThreadUtil.sleepForSeconds(5);
                log.info("task#{} finish");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        executorService.shutdown();
        boolean isFinishedInTimeout = executorService.awaitTermination(1, TimeUnit.SECONDS);
        // false
        log.info("isFinishedIn aWaitTermination Timeout: {}", isFinishedInTimeout);
        log.warn("executorService#shutdown non block");
    }

    @Test
    @DisplayName("test shutdown & awaitTermination")
    public void test4() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> new Thread(r));
        IntStream.range(0,5).boxed().forEach(i->executorService.submit(()->{
            try {
                ThreadUtil.sleepForSeconds(5);
                log.info("task#{} finish");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        executorService.shutdown();
        boolean isFinishedInTimeout = executorService.awaitTermination(100, TimeUnit.SECONDS);
        // true
        log.trace("isFinishedIn aWaitTermination Timeout: {}", isFinishedInTimeout);
        log.warn("executorService#shutdown non block");
    }

    @Test
    @DisplayName("test shutdownNow")
    public void test5() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> new Thread(r));
        IntStream.range(0,20).boxed().forEach(i->executorService.submit(()->{
            try {
                ThreadUtil.sleepForSeconds(5);
                log.info("task#{} finish",i);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        List<Runnable> runnableList = null;
        try {
            runnableList = executorService.shutdownNow();
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.warn("executorService#shutdownNow non block");
        System.out.println(runnableList);
        System.out.println(runnableList.size());
        Thread.currentThread().join();
    }

    @Test
    @DisplayName("test awaitTermination")
    public void test6() throws InterruptedException {
        ThreadUtil.sleepForSeconds(10);

        ExecutorService executorService = new ThreadPoolExecutor(10, 20, 30, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10),
                r -> {
                    Thread thread = new Thread(r);
                    thread.setDaemon(true);
                    return thread;
                });
        IntStream.range(0,20).boxed().forEach(i->executorService.submit(()->{
            try {
                // mock 无法打断
                while (true) {

                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }));

        executorService.shutdown();
        // 打断当前线程
        executorService.awaitTermination(2, TimeUnit.SECONDS);
        log.warn("executorService#shutdown non block");
    }
}
